﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SSharp.Core.DataTypes;

namespace SSharp.Core.Evaluator {
	public static partial class Eval {
		/// <summary>
		/// Abstract evaluators for expressions of the type
		/// (symbol . anything)
		/// The expression must be a valid list; otherwise CanEvaluate will return true but Evaluate will throw an exception.
		/// Construct. See IfEvaluator for an example.
		/// </summary>
		private abstract class SpecialFormEvaluator : Evaluator {
			private readonly Symbol specialSymbol;

			/// <summary>
			/// Constructs the SpecialFormEvaluator and sets the symbol to check for.
			/// </summary>
			protected SpecialFormEvaluator(string specialSymbol) {
				this.specialSymbol = new Symbol(specialSymbol);
			}

			/// <summary>
			/// Unpacks, the parameter list into an object[] array, and calls the new Evaluate.
			/// </summary>
			public EvaluationResult Evaluate(object expression, IEnvironment env) {
				object parameters = ((Cons)expression).cdr;
				object[] unpacked = List.Unpack(parameters).ToArray();
				if (unpacked == null) {
					throw new SyntaxError("Special form " + specialSymbol + " cannot accept . parameters");
				}
				return Evaluate(unpacked, env);

			}

			/// <summary>
			/// Evaluates the expression; the parameters are the array constructed from the entire original, minus the special symbol.
			/// </summary>
			public abstract EvaluationResult Evaluate(object[] parameters, IEnvironment env);

			/// <summary>
			/// Checks that the expression is a cons, and its car is the special symbol
			/// </summary>
			public bool CanEvaluate(object expression) {
				return expression is Cons
					&& specialSymbol.Equals(((Cons)expression).car);
			}
		}
	}
}
